package com.os.core.interceptor.ds;

import com.os.common.annotation.ds.DynamicDatasource;
import com.os.common.utils.MyUtil;
import com.os.core.datasource.DBChangeService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 描述：动态数据源切面
 *
 * @author huxuehao
 **/
@Aspect
@Order(-1) // 该切面应当先于 @Transactional 执行
@Component
public class DatasourceAspect {
    private final DBChangeService dbChangeService ;

    public DatasourceAspect(DBChangeService dbChangeService) {
        this.dbChangeService = dbChangeService;
    }

    @Pointcut("@annotation(com.os.common.annotation.ds.DynamicDatasource)")
    public void DsPointcut() {

    }

    @Before("DsPointcut()")
    public void beforeMethod(JoinPoint joinPoint) {
        Map<String, Object> map = parameterMap(joinPoint);
        DynamicDatasource changeDs = ((MethodSignature)joinPoint.getSignature()).getMethod().getAnnotation(DynamicDatasource.class);
        Object o = map.get(changeDs.value());
        if (MyUtil.isEmpty(o)) {
            return;
        }
        dbChangeService.changeBD(o.toString());
    }

    @After("DsPointcut()")
    public void afterMethod() {
        dbChangeService.changeDefaultBD();
    }

    /**
     * 获取参数map
     * @param joinPoint 切点
     * @return 参数名-参数值的map
     */
    private Map<String, Object> parameterMap(JoinPoint joinPoint) {
        Object[] parameterValues = joinPoint.getArgs();
        String[] parameterNames = ((CodeSignature) (joinPoint.getSignature())).getParameterNames();
        HashMap<String, Object> map = new HashMap<>();
        for (int i = 0; i < parameterNames.length; i++) {
            map.put(parameterNames[i],parameterValues[i]);
        }
        return map;
    }
}
